Imports¶

In [1]:
import wandb
import pandas as pd
import json
from datasets import load_from_disk
import re
import numpy as np
from sklearn.metrics import ConfusionMatrixDisplay, confusion_matrix
import matplotlib.pyplot as plt

from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from langchain.embeddings import HuggingFaceEmbeddings

import plotly.graph_objs as go
import plotly.express as px
from plotly.offline import iplot
import textwrap

from transformers import AutoModelForCausalLM, AutoTokenizer, AutoConfig, BitsAndBytesConfig
from peft import PeftModel, PeftConfig
import torch

from dotenv import load_dotenv
import os
import warnings
import gc
'NoneType' object has no attribute 'cadam32bit_grad_fp32'
/opt/homebrew/Caskroom/miniforge/base/envs/deep-learning/lib/python3.10/site-packages/bitsandbytes/cextension.py:34: UserWarning:

The installed version of bitsandbytes was compiled without GPU support. 8-bit optimizers, 8-bit multiplication, and GPU quantization are unavailable.

Verwendete Modelle¶

Modellarchitektur LLama2 13b¶

Ressourcen:

  • LLaMA explained (Umar Jamil)
  • LLaMA: Open and Efficient Foundation Language Models (Hugo Touvron et al.)
  • Llama 2: Open Foundation and Fine-Tuned Chat Models (Hugo Touvron et al.)

title

Modellarchitektur Mistral 7b¶

Ressourcen:

  • Mistral 7B (Albert Q. Jiang et al.)
  • Mistral source code (Huggingface)

title

Unterschiede Vorteile / Nachteile¶

Die Modellarchitekturen des LLaMA 2 und Mistral unterscheiden sich kaum.
Die Verwendung der RMSnorm, Aufbau des Feedforward-layers, GQA (nur bei LLaMA 2 34/70b) sowie rotary positional Encoding, sind exakt gleich.
Mistral nutzt im Gegensatz zum LLaMA 2 allerdings zusätzlich eine Sliding-Window-Attention.
Vergleicht man die Parameter des Mistral 7b und LLaMA 2 7b, so fällt auf, dass activation function, hidden size, sowie Anzahl attention heads exakt gleich sind.

Unterscheiden tun sich die Modelle in der Art der Attention:

  • LLaMA 2 7b: MHA
  • Mistral 7b: GQA mit SWA

und in der Grösse der intermediate size, da diese des Mistral dasjenige der LLaMA 2 7/13b übersteigen.

Nach Bau et al. befinden sich die factual associations hauptsächlich in den MLP layers.
Mistral nutzt eine grössere intermediate size als die LLaMA 2 7/13b. Möglicherweise können dadurch mehrere factual associations abgespeichert werden.
Dies wäre eine Erklärung weshalb das Mistral in den Benchmarks im Paper von Albert Q. Jiang et al. besser performt als die genannten LLaMA 2 modelle.

Betrachten wir die Anzahl MLP parameter so können wir folgendes beobachten:

$$ MLP\_PARAMS_{Mistral\ 7b} = 32*3*4096*14336 = 5637144576 $$$$ MLP\_PARAMS_{LLaMA2\ 7b} = 32*3*4096*11008 = 4328521728 $$$$ MLP\_PARAMS_{LLaMA2\ 13b} = 40*3*5120*13824 = 8493465600 $$

Das Mistral 7b besitzt mehr Parameter auf den MLPs als das LLaMA 2 7b.
Somit kann das Mistral möglicherweise mehr Informationen aufnehmen als das LLaMA 2 7b.
Das LLaMA 2 13b besitzt allerdings insgesamt mehr Parameter in den MLPs, weshalb man erwarten könnte, dass dies besser performen muss als das Mistral.
Es könnte sein, dass die MLPs in den early Layers ähnlich wie bei CNNs auf kleinere Strukturen und MLPs in den late Layers auf grössere Konzepte achten.
Dies könnte eine Erklärung dafür sein, dass das Mistral trotz weniger MLP Parameter laut den Autoren besser performt als das LLaMA 13b.
Die bessere performance könnte allerdings auch von den Trainingsdaten abhängen.

Das Mistral hat bezüglich Kontext size durch die Verwendung der Sliding-window-attention definitiv einen Vorteil gegenüber den LLaMA models. Dadurch kann Mistral längere Texte als 4096 Tokens verarbeiten.
Die Grouped-query-attention ist ein Tradeoff zwischen Genauigkeit und Geschwindigkeit des Modells, weshalb sowohl LLaMA (allerdings nur das 34 und 70b Modell) als auch die Mistral diese nutzen.
Beide Modelltypen nutzen statt dem vanilla absolute positional encoding das rotary position embedding. Dies hat den Vorteil, dass die Originalen Token-embeddings nicht durch das Positional-encoding kompromitiert werden.
Statt der Layernorm nutzen beide Modelltypen die RMSnorm, welche Effizienter in der Berechnung ist.

Weshalb wurden diese Modelle verwendet¶

TODO: besser begründen wieso diese Wahl getroffen

Wir haben uns aus folgenden Gründen für die LLaMA 2 13b sowie die Mistral 7b entschieden:

  • Sie sind beide Open-source
  • Sie können quantisiert beide auf einer Nvidia RTX 4090 laufen
  • Hohes ranking in chatbot-arena-leaderboard

Methodik¶

Das Ziel¶

Unser Ziel ist es, ein LLM zu entwickeln, welches den Question Answering Pfad unseres Chatbots Data übernehmen kann. Dazu möchten wir ein existierendes LLM so fine-tunen, dass es gestellte Fragen auf zur Verfügung gestelltem Kontext beantworten kann (Retrieval Augmented Generation). Dabei soll das LLM erkennen, ob die zur Beantwortung der Frage notwendigen Informationen im Kontext vorhanden sind, und wenn nicht, die Beantwortung ablehnen (kein pre-trained knowledge verwenden) und diesen Fakt in der Antwort kommunizieren. Der Kontext besteht dabei aus einer Liste von relevanten Chunks, die durch Retrieval aus unserer Vektordatenbank ausgelesen werden. Die Chunks wurden aus den Spaces Daten des Studiengangs Data Science generiert, und enthalten neben dem Text Metadaten wie das Modulkürzel, die vollständige Bezeichnung, die Anzahl ECTS und die Quelle. Das LLM soll in seinen generierten Antworten die Quelle des Chunks angeben, aus dem Informationen zur Beantwortung der Frage verwendet wurden. Damit können Studenten, die den Bot benutzen, bei Bedarf die Antworten des LLMs überprüfen.

Fine-tuning¶

Fine-tuning bezeichnet den Prozess der Anpassung eines bereits vortrainierten Modells (pre-trained model) auf eine spezifische Aufgabe oder Daten, um die Leistungsfähigkeit des Modells für diese Aufgabe zu verbessern. Hierbei wird die generelle Wissensbasis des Modells beibehalten, während es gleichzeitig für die speziellen Anforderungen und Nuancen des neuen Anwendungsbereichs optimiert wird.

Pre-trained Models¶

Modelle wie Llama 2 und Mistral sind vortrainierte Sprachmodelle, die ein breites Verständnis von Sprache und Wissen bieten. Indem wir solche Modelle als Ausgangspunkt nehmen, können wir von dem bereits erworbenen Wissen und den Fähigkeiten des Modells profitieren. Das spart viel Zeit als auch Ressourcen, die wir im Rahmen von NPR gar nicht hätten. Mittels Fine-tuning passen wir diese Modelle an die unter Ziel genannten Bedürfnisse und Daten des Projekts an. Beide Modelle sind auf der Hugging Face Plattform verfügbar. Die Hugging Face Bibliothek transformers bietet uns eine konsistente Schnittstelle zum Arbeiten mit verschiedenen Sprachmodellen.

Wir haben die folgenden Modelle und Datasets von Hugging Face verwendet:

  • Used model (https://huggingface.co/flozi00/Llama-2-13b-german-assistant-v7) | Download: 22.12.2023
  • Used model (https://huggingface.co/meta-llama/Llama-2-13b-hf) | Download: 23.12.2023
  • Used model (https://huggingface.co/VAGOsolutions/SauerkrautLM-7b-v1-mistral) | Download: 29.12.2023
  • Fine-Tuning Dataset Base (https://huggingface.co/datasets/deepset/germanquad) | Download: 22.12.2023, Abstractive dataset modification: 22.12.2023

Quantization und LoRA¶

Beim Fine-tuning müssen verschiedene Faktoren berücksichtigt werden, wie die Modellgrösse im Verhältnis zur verfügbaren GPU-Kapazität. Grössere Modelle benötigen mehr Speicher und Rechenleistung, was die Hardwareanforderungen erhöht und Kosten sowie Zugänglichkeit beeinflusst. Uns steht ein Rechner von Tobias mit einer NVIDIA GeForce RTX 4090 zur Verfügung. Ohne die Anwendung einiger Tricks wäre es uns nicht möglich, die ausgewhählten 7B und 13B Parameter grossen Modelle zu fine-tunen.

Quantization und LoRA (Low-Rank Adaptation) sind Techniken, die helfen, die Effizienz von LLMs zu verbessern, indem sie die Modellgrösse reduzieren oder die Anpassungsfähigkeit erhöhen, ohne signifikante Verluste in der Leistung zu verursachen. Quantization verringert den Speicherbedarf, indem es die Präzision der Gewichte des Modells reduziert. LoRA hingegen ist eine Methode, die die Anzahl der zu trainierenden Parameter reduziert, indem es die Matrizen des Modells in niedrigere Ränge zerlegt.

TODO: weiter ausführen

  • fine-tuning benötigt nochmal deutlich mehr memory wie inference

Quantization erklärt¶

Quantization ist der Prozess der Diskretisierung kontinuierlicher Verteilungswerte in diskrete Werte. Dies bedeutet, dass die kontinuierlichen Gewichte des Modells auf eine festgelegte Anzahl von Werten reduziert werden, was den Speicherbedarf und die Rechenzeit verringert.

Motivation: Der Hauptantrieb hinter Quantization ist die Optimierung der Leistung pro genutztem Bit im Modell. Durch die Reduzierung der Präzision der Gewichte eines Modells können wir eine höhere Effizienz in Speicher und Berechnungen erreichen, was besonders auf Hardware mit begrenzten Ressourcen wie unserer GPU von Bedeutung ist.

4-bit integer Quantization: In unserem Fall verwenden wir 4-bit integer Quantization, was bedeutet, dass jedes Gewicht in unserem Modell auf eines von (2^4 = 16) möglichen Werten reduziert wird. Dies bietet einen guten Kompromiss zwischen Modellleistung und Speichereffizienz.

Blockweise Quantisierung: Eine weitere Optimierungstechnik ist die blockweise Quantisierung, bei der Eingabetensoren in kleinere Blöcke unterteilt werden, die unabhängig voneinander quantisiert werden. Dies ermöglicht eine parallele Verarbeitung über Kerne hinweg, was zu einer schnelleren Optimierung und einer hochpräzisen Quantisierung führt.

Relevante Hyperparameter: Neben der Anzahl der Bits gibt es weitere Variablen, die die Quantisierung verbessern können:

  • Blockgrösse: Je kleiner die Blockgrösse, desto besser können wir unabhängige Quantisierungen erreichen und so die Genauigkeit erhöhen.
  • Datentypen: Auch die Wahl des Datentyps macht einen Unterschied. NormalFloat4 (NF4) zum Beispiel, ist ein informationstheoretisch optimaler Datentyp für Normalverteilungen und kann einen erheblichen Unterschied in der Leistungsfähigkeit machen.

LoRA erklärt¶

Die Kernidee hinter LoRA ist, dass die Änderungen, die während des Fine-tunings an den Gewichten eines Modells vorgenommen werden, durch zwei Matrizen niedriger Rangordnung dargestellt werden können. Dies basiert auf der Annahme, dass es eine lineare Abhängigkeit in den Anpassungen gibt, und folglich kann das Fine-tuning effizienter gemacht werden, indem der Rang dieser Anpassungen reduziert wird.

Technisch gesehen funktioniert LoRA, indem es eine Änderungsmatrix $\triangle{W}$ der Dimensionen $d \times k$ berechnet. Diese Änderungsmatrix wird dann zu den ursprünglichen Modellgewichten hinzugefügt, um sie zu aktualisieren. Die Matrix $\triangle{W}$ wird durch die Multiplikation zweier neuer Matrizen $B$ und $A$ berechnet: $\triangle{W} = B \times A$. Die Dimensionen von $A$ und $B$ sind so gewählt, dass die resultierende Matrix die Dimensionen der Modellgewichte hat, also beispielsweise $d \times r$ für $B$ und $r \times k$ für $A$, wobei $r$ der Rang ist.

Die Matrix $A$ wird in der Regel aus einer Gaussschen Verteilung initialisiert, während $B$ mit Nullen initialisiert wird. Während des Fine-tunings werden dann diese Gewichte durch Backpropagation angepasst, wobei nur die relativ wenigen Parameter in den Matrizen $A$ und $B$ und nicht die gesamten Gewichte des Modells aktualisiert werden.

Einer der Hauptvorteile von LoRA ist, dass es die Parameter Effizienz während des Fine-tunings erheblich verbessert. Anstatt alle Gewichte eines grossen Modells zu aktualisieren, was oft Millionen oder gar Milliarden von Parametern umfasst, werden nur die Gewichte in den niedrigrangigen Matrizen $A$ und $B$ angepasst. Dies führt zu einer drastischen Reduzierung der Anzahl der zu trainierenden Parameter und damit zu einem effizienteren und schnelleren Fine-tuning.

Obwohl LoRA standardmässig auf das Attention Module (insbesondere die Projektionen für Query und Value) angewendet wird (Hu et al., 2021), empfiehlt sich eine Anwendung auf alle Linearen Layer in den Transformer Blöcken (Dettmers et al., 2023), um die volle Leistungsfähigkeit zu erreichen. Die genaue Grösse der Adapter oder die Rangordnung der Matrizen $A$ und $B$ spielt dabei eine untergeordnete Rolle; entscheidend ist vielmehr die Fähigkeit, die relevanten Änderungen während des Fine-tunings effizient zu repräsentieren und zu optimieren.

QLoRa¶

QLoRa kombiniert Quantization und LoRA, und bringt dadurch die beiden Optimierungen zusammen. Im besten Fall bleibt die Performance des Modells sogar gleich wie sie es bei einem vollständigen Fine-tuning wäre (Dettmers et. al., 2023). Insgesamt lässt sich mit QLoRA beispielsweise ein 65B Parameter grosses Modell, welches ursprünglich 780 GB GPU Memory benötigt hätte (ohne Berücksichtigung der Activations während der Backpropagation), auf nur einer grossen Datacenter GPU trainieren. In unserem Fall bedeutet dass, dass wir damit 13B und 7B Modelle wie Llama 2 und Mistral auf der 4090 GPU von Tobias Fine-tunen können.

Training¶

Wir haben QLoRA mit der Hugging Face transformers Library implementiert. Hier sind die Details unserer Fine-tuning Implementierung:

LoRA-Konfiguration:¶

Wir haben LoRAConfig mit spezifischen Parametern eingerichtet:

  • r: 12 - Der Rang für unsere Matrizen A und B, eine kritische Grösse, die die Anzahl der Parameter, die während des Fine-tunings angepasst werden, bestimmt.
  • lora_alpha: 10 - Ein Multiplikationsfaktor für LoRA-Gewichte, der die Skalierung der LoRA-Updates steuert.
  • lora_dropout: 0.1 - Dropout-Rate, um Overfitting während des Trainings zu vermeiden.
  • bias: "none" - Wir haben uns entschieden, keinen Bias in LoRA zu verwenden.
  • task_type: "CAUSAL_LM" - Unser Modell ist auf kausale Sprachmodellierung ausgerichtet.

BitsAndBytes-Konfiguration:¶

Um die Quantisierungseffizienz zu maximieren, haben wir BitsAndBytesConfig eingeführt:

  • load_in_4bit: True - Aktiviert die 4-Bit Quantisierung beim Laden von Modellen.
  • bnb_4bit_use_double_quant: True - Nutzt doppelte Quantisierung für verbesserte Genauigkeit bei 4-Bit Werten.
  • bnb_4bit_quant_type: "nf4" - Spezifiziert den Normal-Float-4-Bit Quantisierungstyp, den wir verwenden.
  • bnb_4bit_compute_dtype: torch.bfloat16 - Legt den Datentyp für die Berechnungen fest, um einen guten Kompromiss zwischen Leistung und Genauigkeit zu gewährleisten.

Trainingseinstellungen:¶

Unser Training wird durch die TrainingArguments und den SFTTrainer gesteuert:

  • output_dir, overwrite_output_dir, per_device_*_batch_size, und andere Standardparameter steuern, wo und wie das Training durchgeführt wird.
  • gradient_accumulation_steps und learning_rate sind fein abgestimmt, um die Effektivität unseres Trainings zu maximieren.
  • logging_steps, num_train_epochs, und lr_scheduler_type sind entscheidend für das Monitoring und die Steuerung des Trainingsverlaufs.
  • evaluation_strategy und save_strategy sind auf "steps" gesetzt, was bedeutet, dass wir regelmässig evaluieren und speichern, um den Fortschritt zu überwachen.
  • load_best_model_at_end: True und metric_for_best_model: "loss" stellen sicher, dass wir am Ende das Modell mit der besten Leistung auswählen.

Der SFTTrainer wird mit unserem Modell, Tokenizer, Daten und spezifischen peft_config für LoRA eingerichtet. Zusätzlich haben wir eine DataCollatorForCompletionOnlyLM eingerichtet, die speziell auf unser Training abgestimmt ist, falls wir nur auf Vervollständigungen trainieren wollen.

Instruction Tuning für Question Answering¶

Beim Instruction Tuning für das Question Answering mit dem Retrieval-Augmented Generation (RAG)-Ansatz werden bestimmte Anweisungen genutzt, um die Leistungsfähigkeit des LLMs bei der Beantwortung von Fragen zu verbessern. Dies geschieht durch die gezielte Ausrichtung des Modells auf eine spezifische Aufgabenstruktur, die in unserem Fall wie folgt aussieht:

[INST] Dir wird eine Frage gestellt, zu der du den passendsten Kontext erhältst. Deine Aufgabe ist es, die Frage anhand dieses Kontexts zu beantworten. [/INST]

[FRAGE] {question} [/FRAGE]

[KONTEXT] {context} [/KONTEXT]

ANTWORT:

Ein entscheidender Aspekt dieser Methodik ist die Integration einer spezifisch formatierten Aufgabenstellung, die die Struktur und den Zweck der Aufgabe klar definiert. Die Anweisung [INST] gibt dem Modell einen klaren Rahmen vor, innerhalb dessen es arbeiten soll: Eine Frage beantworten, indem der bereitgestellte Kontext genutzt wird.

Der [KONTEXT]-Abschnitt enthält eine Sammlung von Informationsquellen, die als Grundlage für die Beantwortung der Frage dienen. Dieser Kontext wird in einem strukturierten Format präsentiert, das aus verschiedenen immer gleich bleibenden Quellen im JSON Format besteht, wie zum Beispiel:

[
   {
      "QUELLE":"Encyclopedia Britannica",
      "INHALT":"Nördlich werden die Great Plains durch den Kanadischen Schild, südlich durch die Küstenebene des Golfes von Mexiko begrenzt. Die westliche Grenze bilden die Rocky Mountains. ..."
   },
   ...
]

Durch die Strukturierung des Kontexts in Quellen und Inhalte kann das Modell relevante Informationen effizient identifizieren und nutzen, um eine genaue und fundierte Antwort zu generieren.

Die Herausforderung beim Instruction Tuning liegt darin, das Modell so anzupassen, dass es nicht nur die Fragestellung versteht, sondern auch in der Lage ist, den Kontext effektiv zu durchsuchen und die relevantesten Informationen für die Beantwortung der Frage herauszufiltern. Dies erfordert ein tiefes Verständnis der Inhalte und der Fähigkeit, Querverbindungen zwischen Frage und Kontext herzustellen. Auch muss es in der Lage sein, am Ende zu identifizieren, welche Quelle anzugeben ist, basierend darauf welche Informationen bei der Generierung der Antwort verwendet wurden.

Das Fine-tuning ist in der Stage train_llm implementiert, und nutzt den modifizierten Germanquad Datensatz nach genau diesem Instruction Tuning Schema.

Evaluation¶

Um die Modelle zu evaluieren, werden wir eine Quantitative und eine Qualitative Analyse durchführen. Die Quantitative Analyse wird uns helfen, die Leistung der Modelle anhand von Metriken zu verstehen und direkt zu vergleichen, während die Qualitative Analyse uns Einblicke in die Stärken und Schwächen der Modelle geben wird, wie sie sich in der Realität verhalten.

Quantitative Analyse¶

Im Rahmen der Quantiativen Analyse werden wir folgendes prüfen:

  • Die Leistung der Modelle auf Traninings-, Validierungs- und Testdaten in einem Weights&Biases gegenüberstellen (Loss, BLEU, ROUGE)
  • Prüfen, wie gut die Modelle Fragen erkennen kann, die nicht beantwortet werden können (Confusion Matrix)
  • Prüfen, wie oft in der Antwort die korrekte Quelle ausgewiesen wird

BLEU-Score¶

Der BLEU-Score ist ein Mass zur Bewertung der Qualität von einem Vorhergesagten Text. Er vergleicht den generierten Text mit einem oder mehreren Referenztexten, um festzustellen, wie ähnlich dieser zu den Referenztexten ist. Die Hauptkomponenten des BLEU-Scores sind:

  • N-Gram-Precision: Precision von N-Grams zwischen der Prediction und den Referenztexten.

  • Clipping: Begrenzt die Anzahl der Übereinstimmenden N-Grams, um übermässige Wiederholungen zu vermeiden.

  • Breite der N-Grams: Berücksichtigt verschiedene N-Gram-Längen, normalerweise bis zu 4-Grams.

  • Brevity Penalty (BP): Strafe für zu kurze Übersetzungen, um übermässig kurze Texte zu vermeiden, die sonst hohe Scores erzielen könnten. Formel: $$ \text{BP} = \begin{cases} 1 & \text{wenn } c > r \\ e^{(1-r/c)} & \text{wenn } c \leq r \end{cases} $$ (c) ist die Länge der Predictions und (r) die effektive Referenzlänge.

  • Berechnung des BLEU-Scores: Der endgültige Score ist das Produkt aus der Brevity Penalty und dem geometrischen Mittel der N-Gram-Precisions: $$ \text{BLEU} = \text{BP} \cdot \exp\left(\sum_{n=1}^{N} w_n \log p_n\right) $$ ($p_n$) ist die Precision für N-Grams, ($w_n$) das Gewicht für jedes N-Gram $=1/N$, und ($N$) die maximale N-Gram-Länge.

Der Bleu score liegt im Intervall [0, 1] wobei dieser 1 ist, wenn die Prediction und Referenz genau gleich sind.
Der beste Score welcher realistisch erreicht werden kann liegt um die 0.6 - 0.7.
Der Bleu score hat keine Context awareness. Bedeutet, dass er den Inhalt der Texte nicht versteht und daher auch schwerwiegende Fehler machen kann.
Beispielsweise würde er bei "Ich werde übermorgen zusammen mit meiner Freundin ins Kino gehen" und "Ich werde übermorgen nicht zusammen mit meiner Freundin ins Kino gehen" einen hohen score anzeigen,
obwohl die Sätze komplett verschiedene Bedeutungen haben.
Der Bleu score konzentriert sich auf die Präzision. Es misst, wie viele Wörter oder Phrasen im generierten Text mit den Wörtern oder Phrasen in den Referenztexten übereinstimmen. Höhere BLEU-Werte deuten darauf hin, dass der generierte Text den Referenztexten ähnlicher ist.

ROUGE-Score¶

Der Rouge-Score ist eine Metrik, die in der Zusammenfassung von Texten häufig verwendet wird. Es handelt sich um eine Familie von Massen, die die Qualität einer generierten Zusammenfassung im Vergleich zu einer oder mehreren Referenzzusammenfassungen bewertet. Die verschiedenen Varianten des Rouge-Scores erfassen unterschiedliche Aspekte der Ähnlichkeit zwischen den Zusammenfassungenn:

  1. ROUGE-N: Der ROUGE-N Score berechnet sich als ein Verhältnis der Anzahl der übereinstimmenden N-Gramme zur Gesamtzahl der N-Gramme in der Referenzzusammenfassung. Die Formel für ROUGE-N ist: $$ \text{ROUGE-N} = \frac{\sum_{s \in \{\text{Referenzsätze}\}} \sum_{ngram \in s} \text{Count}_{\text{match}}(ngram)}{\sum_{s \in \{\text{Referenzsätze}\}} \sum_{ngram \in s} \text{Count}(ngram)} $$ Dabei ist ($\text{Count}_{\text{match}}(ngram)$) die Anzahl der N-Gramme, die in der generierten Zusammenfassung und der Referenzzusammenfassung übereinstimmen.

  2. ROUGE-L: ROUGE-L verwendet die längste gemeinsame Teilsequenz (LCS). Die Formel für ROUGE-L ist:

    $$ \text{LCS}(A, B) = \begin{cases} 0, & \text{wenn } A \text{ oder } B \text{ leer ist} \\ 1 + \text{LCS}(\text{Rest von } A, \text{Rest von } B), & \text{wenn das erste Element von } A \text{ und } B \text{ gleich ist} \\ \max(\text{LCS}(A, \text{Rest von } B), \text{LCS}(\text{Rest von } A, B)), & \text{anderenfalls} \end{cases} $$$$ \text{ROUGE-L} = \frac{\sum_{s \in \{\text{Referenzsätze}\}} \text{LCS}(s, \text{Generierte Zusammenfassung})}{\sum_{s \in \{\text{Referenzsätze}\}} \text{Länge}(s)} $$

    Hierbei ist ($\text{LCS}(s, \text{Generierte Zusammenfassung})$) die Länge der längsten gemeinsamen Teilsequenz zwischen einem Satz ($s$) der Referenzzusammenfassung und der generierten Zusammenfassung.

  3. ROUGE-W: ROUGE-W berücksichtigt die Gewichtung der Länge der gemeinsamen Teilsequenzen. Die Formel sieht wie folgt aus: $$ \text{ROUGE-W} = \frac{\sum_{s \in \{\text{Referenzsätze}\}} \text{WLCS}(s, \text{Generierte Zusammenfassung})}{\sum_{s \in \{\text{Referenzsätze}\}} \text{Länge}(s)} $$ ($\text{WLCS}$) ist die gewichtete längste gemeinsame Teilsequenz, die längeren Teilsequenzen mehr Gewicht gibt.

Der Rouge score liegt im Intervall [0, 1]. Dieser fokussiert sich auf die Recall-Rate, also die Wiederfindungsrate. Es bewertet, wie viel vom Inhalt der Referenzzusammenfassung in der generierten Zusammenfassung enthalten ist. Höhere ROUGE-Werte zeigen an, dass die generierte Zusammenfassung mehr vom Inhalt der Referenzzusammenfassungen abdeckt.

TODO überprüfen ob formeln/aussagen stimmen

Qualitative Analyse¶

In der Qualitativen Analyse stellen wir zwei unterschiedliche Kontexte mit jeweils 3 Context Blocks (Document Chunk mit Metadaten) zusammen und stellen dem Modell Fragen, die sich auf die einzelnen Context Blocks beziehen können oder auch nicht. Wir werden die Antworten des Modells mit den erwarteten Antworten vergleichen und auf ihre Korrektheit und Verständlichkeit prüfen. Die Qualitative Analyse wird uns helfen, die Stärken und Schwächen der Modelle zu verstehen und zu vergleichen.

Ein Kontext Block besteht aus thematisch ähnlichen Chunks, während der andere Kontext Block thematisch unterschiedliche Chunks enthält.

Dabei prüfen wir folgende Kriterien:

  • Genauikeit der Informationen
  • Vollständigkeit der Antwort
  • Verständlichkeit

EDA Datenset¶

Analyse

In [8]:
ft_data = pd.DataFrame(load_from_disk("data/processed/ft_dataset_abstractive.hf/", keep_in_memory=True))
ft_data.head()
Out[8]:
context question extractive_answer can_be_answered split sourced_context abstractive_answer
0 Elisabeth ist Schirmherrin von über 600 wohltä... Ab wann wurde die Bezeichnung Kubisten benutzt? Leider liegen mir dazu keine Informationen vor False train [{"QUELLE": "Buckingham Palace", "INHALT": "El... Leider kann ich Ihnen keine genaue Antwort auf...
1 Das Königreich Tibet entstand Anfang des 7. Ja... Wann wurde das Königreich Tibet gegründet? Anfang des 7. Jahrhunderts True train [{"QUELLE": "und 9. Jahrhundert erreichte das ... Das Königreich Tibet wurde Anfang des 7. Jahrh...
2 Der Black Heritage Trail verbindet auf einer L... Wo beginnt der Black Heritage Trail in Boston? an der Faneuil Hall True train [{"QUELLE": "The Black Heritage Trail: A Guide... Der Black Heritage Trail in Boston beginnt an ...
3 In North Carolina wurden eine Reihe bedeutende... Welche bedeutende Künstler wurden in North Car... Sowohl die Schauspielerin Ava Gardner (1922–19... True train [{"QUELLE": "Wikipedia", "INHALT": "In North C... In North Carolina wurden bedeutende Künstler w...
4 Neben der Hauptstadt Juneau sind Anchorage, di... Welches ist die bevölkerungsreichste Stadt in ... Anchorage True train [{"QUELLE": "Wikipedia", "INHALT": "Neben der ... Die bevölkerungsreichste Stadt in Alaska ist A...

Distribution of Abstractive Answer length¶

In [18]:
fig = px.box(ft_data, x=ft_data["abstractive_answer"].apply(lambda x: len(x.split())))
fig.update_layout(
    title_text='Distribution of abstractive answer length',
    xaxis_title_text='Length',
    yaxis_title_text='Count',
    bargap=0.2,
)
fig.show()

# another boxplot, separating by can_be_answered
fig = px.box(ft_data, x=ft_data["abstractive_answer"].apply(lambda x: len(x.split())), color=ft_data["can_be_answered"])
fig.update_layout(
    title_text='Distribution of abstractive answer length',
    xaxis_title_text='Length',
    yaxis_title_text='Count',
    bargap=0.2,
)
fig.show()

Die meisten Antworten sind zwischen 14 und 27 Worte lang, wobei die Antworten im Schnitt kürzer ausfallen, wenn can_be_answered False ist. Das ist zu erwarten, da die meisten Antworten in diesem Fall nur aus einem Satz bestehen, der die Frage verneint.

Auffallend ist, dass es trotzdem einige Antworten mit can_be_answered=False und einer Länge von über 80 Wörtern gibt. Wir sind dem nachgegangen, und haben festgestellt, dass es sich dabei um Fälle handelt, wo GPT-3.5 die Aufgabe nicht verstanden hat (unsere Prompt war nicht optimal), und fälschlicherweise eine Antwort mit pre-trained Knowledge generiert hat. Das ist ein Problem für unser Fine-tuning, da dem Modell so nicht ganz klar wird, ob es antworten darf wenn Kontext fehlt. Leider haben wir erst nach dem Fine-tuning gemerkt, dass diese Fälle existieren, und konnten sie nicht mehr aus dem Datenset entfernen. Diese Korrektur wäre eine low-hanging fruit für zukünftige Arbeiten.

In [29]:
# filter for can_be_answered=False where longer than 200 words, and print
df_filtered = ft_data[(ft_data["can_be_answered"] == False) & (ft_data["abstractive_answer"].apply(lambda x: len(x.split())) > 100)]

# loop and print question, extractive answer, abstractive answer
for i, row in df_filtered.iterrows():
    print(row["question"])
    print(row["extractive_answer"])
    print(row["abstractive_answer"])
    print("")
Warum können Tauschbörsen für Filme nicht richtig verboten werden?
Leider liegen mir dazu keine Informationen vor
Es gibt verschiedene Gründe, warum Tauschbörsen für Filme nicht richtig verboten werden können. Ein Grund ist, dass es schwierig ist, die Betreiber solcher Tauschbörsen zu identifizieren und rechtlich zu verfolgen. Oftmals operieren sie anonym im Internet und nutzen Technologien wie VPNs, um ihre Identität zu verschleiern. Zudem können Tauschbörsen leicht ihre Serverstandorte ändern, um den Behörden auszuweichen. Ein weiterer Grund ist, dass es schwierig ist, die Nutzer solcher Tauschbörsen zu ermitteln und zu bestrafen. Oftmals handelt es sich um eine große Anzahl von Personen, die Filme illegal herunterladen oder hochladen, und es ist ressourcenintensiv, gegen jeden einzelnen vorzugehen. Darüber hinaus gibt es auch technische Möglichkeiten, um die Überwachung und Verfolgung von Tauschbörsen zu erschweren, wie beispielsweise die Verwendung von verschlüsselten Verbindungen. Insgesamt ist es eine komplexe und herausfordernde Aufgabe, Tauschbörsen für Filme effektiv zu verbieten.

Welchen Einfluss hat Architektur auf Menschen?
Leider liegen mir dazu keine Informationen vor
Die Architektur eines Gebäudes kann einen erheblichen Einfluss auf Menschen haben. Sie kann das Wohlbefinden, die Produktivität und die Stimmung der Menschen beeinflussen. Eine gut gestaltete Architektur kann eine positive Umgebung schaffen, die das Wohlbefinden fördert und die Interaktion und Kommunikation zwischen den Menschen erleichtert. Eine schlecht gestaltete Architektur kann hingegen zu Unbehagen, Stress und sogar gesundheitlichen Problemen führen. Es gibt viele Aspekte der Architektur, die den Einfluss auf Menschen bestimmen, wie zum Beispiel die Raumgestaltung, die Nutzung von Licht und Farben, die Akustik und die Zugänglichkeit. Es ist wichtig, dass Architekten diese Faktoren bei der Gestaltung von Gebäuden berücksichtigen, um eine positive Umgebung für die Menschen zu schaffen.

Warum gibt es auf den estnischen Inseln fast keine russischsprachige Bevölkerung?
Leider liegen mir dazu keine Informationen vor
Es gibt verschiedene Gründe, warum es auf den estnischen Inseln möglicherweise nur eine geringe russischsprachige Bevölkerung gibt. Ein möglicher Grund könnte die historische Entwicklung sein, da Estland während der sowjetischen Besatzungszeit von 1940 bis 1991 stark russifiziert wurde. Dies führte zu einer Abwanderung vieler Esten und einer verstärkten Zuwanderung von Russen in das Land. Es ist möglich, dass die estnischen Inseln aufgrund ihrer geografischen Lage und begrenzten Ressourcen weniger attraktiv für russischsprachige Einwanderer waren. Es könnte auch kulturelle und sprachliche Unterschiede geben, die dazu beitragen, dass sich die russischsprachige Bevölkerung eher in anderen Teilen Estlands konzentriert. Es ist jedoch wichtig zu beachten, dass dies nur spekulative Gründe sind und weitere Forschung erforderlich wäre, um eine genaue Antwort auf diese Frage zu geben.

Warum kam es in der Schweiz nie zu einem eigenständigen Musikstil?
Leider liegen mir dazu keine Informationen vor
Es gibt verschiedene Gründe, warum es in der Schweiz nie zu einem eigenständigen Musikstil gekommen ist. Einerseits ist die Schweiz ein kleines Land mit einer vielfältigen kulturellen Landschaft, in der verschiedene musikalische Traditionen und Einflüsse aus anderen Ländern existieren. Andererseits hat die Schweiz eine lange Tradition der kulturellen Vielfalt und des kulturellen Austauschs, was dazu führt, dass sich verschiedene Musikstile aus anderen Ländern etabliert haben. Zudem ist die Schweiz geografisch und sprachlich vielfältig, was dazu führt, dass sich verschiedene regionale Musikstile entwickelt haben. Insgesamt kann man sagen, dass die Schweiz eher von einer Vielfalt an Musikstilen geprägt ist, anstatt von einem einheitlichen eigenständigen Stil.

Warum haben sich Pflanzen in die hochalpinen Gebiete zurück gezogen? 
Leider liegen mir dazu keine Informationen vor
Es gibt verschiedene Gründe, warum sich Pflanzen in hochalpine Gebiete zurückziehen könnten. Dazu gehören unter anderem die klimatischen Bedingungen, wie niedrige Temperaturen, starke Winde und kurze Vegetationsperioden. Diese Bedingungen können für viele Pflanzenarten extrem herausfordernd sein. Pflanzen, die in der Lage sind, sich an diese extremen Bedingungen anzupassen, können in den hochalpinen Gebieten überleben. Ein weiterer Grund könnte sein, dass die Konkurrenz durch andere Pflanzenarten in tieferen Lagen geringer ist, was den Pflanzen in den hochalpinen Gebieten einen Vorteil verschafft. Es ist jedoch wichtig anzumerken, dass dies nur allgemeine Gründe sind und es von Pflanzenart zu Pflanzenart unterschiedliche spezifische Gründe geben kann.

Warum wurde die AdCSV zum standardverfahren? 
Leider liegen mir dazu keine Informationen vor
Die AdCSV wurde zum Standardverfahren, um die Daten auf der CD mit einer passenden Kanalkodierung zu kodieren. Diese Kodierung, auch bekannt als Eight-to-Fourteen-Modulation (EFM), berücksichtigt die Eigenheiten des Speichermediums, wie die optische Abtastung und die Form und Größe der Pits. Die EFM sorgt dafür, dass sich alle drei bis elf Bitdauern die Polarität des ausgelesenen Signals ändert, um eine zuverlässige Datenübertragung zu gewährleisten. Durch diese Modulation kann eine hohe Datenrate erreicht werden, und unmodulierte Daten können nicht mehr in Pits und Land aufgelöst werden. Die AdCSV ist also eine Designentscheidung, die für die Spieldauer und die Vereinfachung der Signalverarbeitung verantwortlich ist.

Welcher Zusammenhang steht zwischen Kultur und den Menschenrechten? 
Leider liegen mir dazu keine Informationen vor
Es gibt einen engen Zusammenhang zwischen Kultur und den Menschenrechten. Die Kultur eines Landes kann die Werte, Normen und Überzeugungen beeinflussen, die die Grundlage für die Achtung der Menschenrechte bilden. Eine Kultur, die die Gleichheit, Freiheit und Würde aller Menschen respektiert, fördert in der Regel auch die Einhaltung der Menschenrechte. Auf der anderen Seite können kulturelle Praktiken und Traditionen, die Diskriminierung, Unterdrückung oder Gewalt gegen bestimmte Gruppen fördern, die Menschenrechte verletzen. Es ist wichtig, dass Regierungen und die internationale Gemeinschaft Maßnahmen ergreifen, um sicherzustellen, dass kulturelle Praktiken im Einklang mit den Menschenrechten stehen und dass alle Menschen gleichberechtigt und frei von Diskriminierung behandelt werden.

Warum sollte man keine Insekten aufgrund ästhetischer Vorlieben sammeln?
Leider liegen mir dazu keine Informationen vor
Es gibt verschiedene Gründe, warum man keine Insekten aufgrund ästhetischer Vorlieben sammeln sollte. Ein Grund ist, dass das Sammeln von Insekten zu ihrem Rückgang in der Natur beitragen kann. Viele Insektenarten sind bereits bedroht oder gefährdet, und das Sammeln von ihnen kann ihre Populationen weiter dezimieren. Darüber hinaus spielen Insekten eine wichtige Rolle in Ökosystemen, indem sie als Bestäuber, Schädlingsbekämpfer und Nahrungsquelle für andere Tiere dienen. Das Sammeln von Insekten kann auch ethische Bedenken aufwerfen, da es ihr Leben und ihre Freiheit beeinträchtigt. Es ist daher ratsam, Insekten in ihrer natürlichen Umgebung zu belassen und ihre Schönheit und Vielfalt dort zu bewundern.

PCA and t-SNE reduced embeddings of sourced context¶

In [2]:
references = pd.DataFrame(load_from_disk("data/processed/ft_dataset_abstractive.hf/", keep_in_memory=True).filter(lambda x: x['split'] == "test")) # get test split
Filter:   0%|          | 0/4700 [00:00<?, ? examples/s]
In [3]:
def tsne_reduction_interactive(series: pd.Series, title: str, classes=None, pca_dim=50, perplexity=30, learning_rate=200, seed=1234):
    # Embeddings erstellen
    embeddings = np.array(HuggingFaceEmbeddings(model_name="sentence-transformers/distiluse-base-multilingual-cased-v1").embed_documents(series.to_list()))
    wrapped_text = series.apply(lambda x: '<br>'.join(textwrap.wrap(x, width=50)))

    # Dimensionsreduktion mittels PCA
    pca = PCA(n_components=pca_dim, random_state=seed)
    pca_result = pca.fit_transform(embeddings)

    # Anwendung von t-SNE
    tsne = TSNE(perplexity=perplexity, learning_rate=learning_rate, n_iter=300, random_state=seed)
    tsne_result = tsne.fit_transform(pca_result)

    # Farbkarte und einzigartige Klassen erstellen
    if classes is not None:
        unique_classes = list(set(classes))
        colors = px.colors.qualitative.Plotly
        color_map = {k: colors[i % len(colors)] for i, k in enumerate(unique_classes)}
    else:
        unique_classes = [None]
        color_map = {None: 'blue'}

    # Erstellen der Plotly-Figur
    fig = go.Figure()

    for cls in unique_classes:
        if cls is None:
            idx = list(range(len(series)))
        else:
            idx = [i for i, c in enumerate(classes) if c == cls]

        fig.add_trace(go.Scatter(
            x=tsne_result[idx, 0], 
            y=tsne_result[idx, 1], 
            mode='markers',
            marker=dict(
                size=5, 
                color=color_map[cls], 
                opacity=0.8),
            name=str(cls) if cls is not None else "Unklassifiziert",
            text=[wrapped_text[i] for i in idx]
        ))
        
    # Layout anpassen
    fig.update_layout(
        title=title,
        xaxis_title='Dimension 1',
        yaxis_title='Dimension 2',
        width=1000, height=1000,
        margin=dict(l=40, r=40, t=40, b=40),
        legend_title='Klassen'
    )

    # Visualisierung anzeigen
    iplot(fig)

tsne_reduction_interactive(references.sourced_context, 'PCA and t-SNE reduced embeddings of sourced context of test data', ["answerable" if e else "not answerable" for e in references.can_be_answered.values])

Wie auf dem PCA und t-SNE Plot schön zu sehen ist, sind die Beispiele im Datensatz wo Fragen beantwortet werden können und wo nicht, thematisch sehr unterschiedlich (repräsentiert durch die Verteilung). Damit ist sichergestellt, dass das Modell nicht eifach auswendig lernt, auf bestimmte Themenbereiche keine Antwort zu geben. Dass Beispiele mit ähnlichen Themen näher beeinander liegen, zeigt sich zum Beispiel gut einer Gruppe von Samples in der unteren linken Ecke, wo sich jeweils mindestens ein Kontext auf das Thema Afrika bezieht.

Resultate¶

Quantitiative Analyse¶

Siehe eingebetteter W&B Report.